package cn.itsource.pethome.system.logininfo.service.impl;

import cn.itsource.pethome.jwt.PayloadData;
import cn.itsource.pethome.system.employee.domain.Employee;
import cn.itsource.pethome.system.employee.domain.EmployeeBo;
import cn.itsource.pethome.system.employee.mapper.EmployeeMapper;
import cn.itsource.pethome.system.logininfo.domain.LoginBO;
import cn.itsource.pethome.system.logininfo.domain.LoginDTO;
import cn.itsource.pethome.system.logininfo.domain.LoginVO;
import cn.itsource.pethome.system.logininfo.domain.Logininfo;
import cn.itsource.pethome.system.logininfo.mapper.LogininfoMapper;
import cn.itsource.pethome.system.logininfo.service.ILogininfoService;
import cn.itsource.pethome.base.service.impl.BaseServiceImpl;
import cn.itsource.pethome.system.menu.domain.Menu;
import cn.itsource.pethome.system.menu.service.IMenuService;
import cn.itsource.pethome.system.permission.domain.Permission;
import cn.itsource.pethome.system.role.mapper.RoleMapper;
import cn.itsource.pethome.system.user.domain.User;
import cn.itsource.pethome.system.user.domain.UserBO;
import cn.itsource.pethome.system.user.mapper.UserMapper;
import cn.itsource.pethome.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author itsource
 * @since 2023-01-12
 */
@Service
public class LogininfoServiceImpl extends BaseServiceImpl<Logininfo> implements ILogininfoService {
    @Resource
    private LogininfoMapper logininfoMapper;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private EmployeeMapper employeeMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Value("${jwt.rsa.pri}")
    private String pri;
    @Resource
    private IMenuService menuService;

    /**
     * 用户名可以是 手机号，邮箱，用户名
     * @param login
     * @return
     */
    @Override
    public AjaxResult account(LoginDTO login) {
        Integer type = login.getType();
        String username = login.getUsername();
        String password = login.getPassword();
        //数据校验
        if(type == null)
            return AjaxResult.error().setMsg("非法访问！");
        if (username == null || "".equals(username.trim()))
            return AjaxResult.error().setMsg("用户名不能为空");
        if (password == null || "".equals(password.trim()))
            return AjaxResult.error().setMsg("密码不能为空");
        //验证密码
        Logininfo account = logininfoMapper.findAccount(login);
        if(account == null)
            return AjaxResult.error().setMsg("用户名或者密码错误！");//防止拿账号一直刷
        String salt = account.getSalt();
        //如果是自动登录，就不用判断密码
        if(!login.getAutoLogin()){
            if (!account.getPassword().equals(MD5Utils.encrypByMd5(password + salt)))
                return AjaxResult.error().setMsg("用户名或者密码错误！");
        }
        return jwtToken(account);
    }

    private AjaxResult jwtToken(Logininfo account) {
        LoginVO loginVO = new LoginVO();//返回给前端的对象
        //获取私钥
        PrivateKey privateKey = null;
        PayloadData payloadData = new PayloadData();
        try {
            privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(pri).getFile());

        //判断是不是管理员
        if(account.getType() == 0){
            EmployeeBo employeeBo = employeeMapper.findByLoginId(account.getId());
            Employee employee = new Employee();
            BeanUtils.copyProperties(employeeBo,employee);
            payloadData.setAdmin(employee);
        }else {
            User user = new User();
            UserBO userBO = userMapper.findByLoginId(account.getId());
            BeanUtils.copyProperties(userBO,user);
            payloadData.setUser(user);
        }
        //获取权限列表
        Long roleId = employeeMapper.findRoleIdByLogininfoId(account.getId());
        List<String> permissions = roleMapper.findPermissions(roleId);
        //设置权限列表到载荷中
        payloadData.setPermissions(new HashSet<>(permissions));
        //获取菜单。重点：传递给前端的数据要包含一级菜单和二级菜单，所以要返回一个菜单树
        List<Menu> all = menuService.findAll();//全部菜单
        List<Menu> myMenus = roleMapper.getMenuByRoleId(roleId);//属于当前账号的菜单（只包含二级菜单）
        //构建菜单树
        List<Long> parentId = myMenus.stream()
                .map(Menu::getParentId)
                .distinct()
                .collect(Collectors.toList());//筛选出去重的所有的一级菜单id

        List<Menu> menuTree = new ArrayList<>();
        parentId.forEach(p-> {
            all.forEach(a->{
                if (a.getId().equals(p))
                    menuTree.add(a);
            });
        });//筛选出一级菜单

        menuTree.forEach(menu -> {
            myMenus.forEach(my->{
                if (Objects.equals(my.getParentId(), menu.getId()))
                    menu.getChildren().add(my);
            });
        });//将自己的菜单填充到对应的一级菜单中，得到完整的菜单树

        payloadData.setMenus(menuTree);
        //获取加密后的token包含载荷（权限，菜单），密钥，过期时间
        String token = JwtUtils.generateTokenExpireInMinutes(payloadData, privateKey, 30);
        //封装用户信息和token传递给前端
        LoginBO loginBO = new LoginBO();
        BeanUtils.copyProperties(account,loginBO);
        loginVO.setLogininfo(loginBO);
        loginVO.setToken(token);
        loginVO.setAdmin(payloadData.getAdmin());
        loginVO.setUser(payloadData.getUser());
        loginVO.setMenus(payloadData.getMenus());
        loginVO.setPermissions(payloadData.getPermissions());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return AjaxResult.success().setData(loginVO).setMsg("userLogin");
    }

    //redis的token方法
    private AjaxResult redisToken(Logininfo account) {
        //用户信息存入redis,30分钟过期
        String token = StrUtils.getComplexRandomString(128);
        redisTemplate.opsForValue().set(token, account,30, TimeUnit.MINUTES);
        //将用户拥有的权限存入redis
        Long roleId = employeeMapper.findRoleIdByLogininfoId(account.getId());
        List<String> permissions = roleMapper.findPermissions(roleId);
        redisTemplate.opsForValue().set(token+"Permission",permissions,30, TimeUnit.MINUTES);

        //封装用户信息和token传递给前端
        LoginVO loginVO = new LoginVO();
        LoginBO loginBO = new LoginBO();
        BeanUtils.copyProperties(account,loginBO);
        loginVO.setLogininfo(loginBO);
        loginVO.setToken(token);
        return AjaxResult.success().setData(loginVO).setMsg("userLogin");
    }
}
